package com.tan.steamship.aspect;

import com.alibaba.fastjson.JSON;
import com.tan.steamship.util.IpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLDecoder;

/**
 * @author tanlongjie
 * @Desc
 * @date 2024/11/25
 * @since 1.0
 */
@Aspect
@Component
@Slf4j(topic = "sys-user")
public class LogAspect {

    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpServletResponse response;

    /**
     * 配置切入点表达式
     */
    @Pointcut("execution(* com.tan.steamship.controller..*(..))")
    public void webData() {
    }

    /**
     * 后置通知
     */
    //@AfterReturning(value = "webData()", returning = "resultData")
    public void beforeWebData(JoinPoint joinPoint, Object resultData) {
        //handleLog(joinPoint, null, resultData);
    }

    /**
     * 异常通知
     *
     * @param joinPoint
     * @param ex        异常
     */
    //@AfterThrowing(value = "webData()", throwing = "ex")
    public void afterThrowingWebData(JoinPoint joinPoint, Exception ex) {
        //handleLog(joinPoint, ex, null);
    }

    @Around(value = "webData()")
    public Object aroundWebData(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long millis = System.currentTimeMillis();
        Object result = null;
        Exception ex = null;
        String param = "";
        try {
            param = getRequestParams(proceedingJoinPoint, request.getMethod());
            result = proceedingJoinPoint.proceed();
        } catch (Exception e) {
            ex = e;
            throw e;
        } finally {
            handleLog(proceedingJoinPoint, ex, result, param, millis);
        }
        return result;
    }

    /**
     * 处理日志
     */
    protected void handleLog(final JoinPoint joinPoint, final Exception e, final Object resultData, final String params, long millis) {
        try {
            //请求地址
            String url = request.getRequestURI();
            // 获取当前的用户
            String employeeCode = null;
            if (StringUtils.isEmpty(url)){
                employeeCode = "";
            }
            // 请求的地址
            String ip = IpUtils.getRemoteIP(request);
            // 返回参数
            String resStr = JSON.toJSONString(resultData);

            // 设置方法名称
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            // 设置请求方式
            String method = request.getMethod();
            //请求参数
            //String params = getRequestParams(joinPoint, method);
            long ms = System.currentTimeMillis() - millis;
            String info = "ip:"+  "[" + ip + "],request:[" + method + "],[耗时:" + ms + "][" + employeeCode + "]," +
                    "url:[" + url + "],method:[" + className + "." + methodName + "()],params:" + params + ",";
            //返回结果
            if (e != null) {
                info += "Exception:[" + e.getMessage() + "]";
                log.info(info);
            } else {
                info += "resultData:" + (resStr.length() > 2000 ? "数据太长不打印" : resStr);
                log.info(info);
            }
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("日志异常信息:", exp);
        }
    }

    /**
     * 获取请求的参数
     *
     * @throws Exception 异常
     */
    private String getRequestParams(JoinPoint joinPoint, String method) throws Exception {
        String params = "";
        if (HttpMethod.PUT.name().equals(method) || HttpMethod.POST.name().equals(method)) {
            params = argsArrayToString(joinPoint.getArgs());
        } else {
            String decode = "";
            if (request.getQueryString() != null) {
                decode = URLDecoder.decode(request.getQueryString(), "utf-8");
            }
            params = "{" + decode + "}";
            //Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        }
        return params;
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if (!isFilterObject(paramsArray[i])) {
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
                    params += (jsonObj != null ? jsonObj.toString() : "") + " ";
                }
            }
        }
        return params.trim();
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }
}
